package com.wzh.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>
 * 网关全局日志记录过滤器，用于记录请求和响应的详细信息，便于调试和监控
 * </p>
 *
 * @author 山归岿
 * @create 2025-06-15-19:42
 */
@Slf4j
@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestId = request.getId();
        String method = request.getMethod().name();
        String url = request.getURI().toString();
        String clientIp = getClientIp(request);

        long startTime = System.currentTimeMillis();

        log.info("[{}] 请求开始 - Method: {}, URL: {}, ClientIP: {}, Headers: {}",
                requestId, method, url, clientIp, request.getHeaders());

        // 记录请求体（仅对POST、PUT等有请求体的方法）
        if (hasRequestBody(method)) {
            return logRequestBody(exchange, chain, requestId, startTime);
        } else {
            return logResponse(exchange, chain, requestId, startTime);
        }
    }

    private boolean hasRequestBody(String method) {
        return "POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method);
    }

    private Mono<Void> logRequestBody(ServerWebExchange exchange, GatewayFilterChain chain,
                                      String requestId, long startTime) {
        ServerHttpRequest request = exchange.getRequest();

        return DataBufferUtils.join(request.getBody())
                .defaultIfEmpty(exchange.getResponse().bufferFactory().allocateBuffer(0))
                .flatMap(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    DataBufferUtils.release(dataBuffer);

                    String requestBody = new String(bytes, StandardCharsets.UTF_8);
                    log.info("[{}] 请求体: {}", requestId, requestBody);

                    DataBufferFactory requestBufferFactory = exchange.getResponse().bufferFactory();
                    DataBuffer wrappedBuffer = requestBufferFactory.wrap(bytes);

                    //构建新的请求对象并替换body
                    ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(request) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return Flux.just(wrappedBuffer);
                        }
                    };

                    // 创建新的exchange对象
                    ServerWebExchange mutatedExchange = exchange.mutate()
                            .request(mutatedRequest)
                            .build();

                    return logResponse(mutatedExchange, chain, requestId, startTime);
                });
    }


    private Mono<Void> logResponse(ServerWebExchange exchange, GatewayFilterChain chain,
                                   String requestId, long startTime) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();

        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(org.reactivestreams.Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux<? extends DataBuffer> fluxBody) {

                    AtomicReference<String> responseBody = new AtomicReference<>();

                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);

                        String bodyContent = new String(content, StandardCharsets.UTF_8);
                        responseBody.set(bodyContent);

                        long endTime = System.currentTimeMillis();
                        long duration = endTime - startTime;

                        log.info("[{}] 请求结束 - Status: {}, Duration: {}ms, ResponseBody: {}",
                                requestId, originalResponse.getStatusCode(), duration, bodyContent);

                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };

        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    private String getClientIp(ServerHttpRequest request) {
        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeaders().getFirst("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp;
        }

        return request.getRemoteAddress() != null ?
                request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
    }

    @Override
    public int getOrder() {
        // 确保在其他过滤器之前执行
        return -1;
    }
}